package main

import (
	"fmt"
	"net/http"
	"sync"
	"time"

	"github.com/gin-gonic/gin"
)

// 定义一个互斥锁，用于在广播通知时同步对clients的访问。
var mu sync.Mutex

// clients是一个保存所有客户端连接的映射，键是客户端的通信信道，值是一个布尔值表示状态。
var clients = make(map[chan string]bool)

// broadcastNotification向所有连接的客户端广播通知消息。
func broadcastNotification(msg string) {
	// 加锁以确保并发安全。
	mu.Lock()
	defer mu.Unlock()
	// 遍历所有客户端，向它们发送消息。
	for client := range clients {
		client <- msg
	}
}

// handleEvents处理客户端的事件流请求，保持连接开放并实时发送事件数据。
func handleEvents(c *gin.Context) {
	// 设置响应头，指明这是一个事件流。
	c.Header("Content-Type", "text/event-stream")
	c.Header("Cache-Control", "no-cache")
	c.Header("Connection", "keep-alive")

	// 创建一个信道，用于向该客户端发送消息。
	clientChan := make(chan string)
	defer close(clientChan)

	// 加锁以确保并发安全。
	mu.Lock()
	clients[clientChan] = true
	mu.Unlock()

	// 检查是否支持Flush操作。
	flusher, ok := c.Writer.(http.Flusher)
	if !ok {
		http.Error(c.Writer, "Streaming unsupported!", http.StatusInternalServerError)
		return
	}

	// 启动一个goroutine监听clientChan，并向客户端发送数据。
	go func() {
		for msg := range clientChan {
			c.Writer.WriteString(fmt.Sprintf("data: %s\n\n", msg))
			flusher.Flush()
		}
	}()

	// 保持连接开放，定期检查客户端是否还在线。
	for {
		time.Sleep(time.Second)
		if _, err := c.Writer.Write([]byte{}); err != nil {
			delete(clients, clientChan)
			break
		}
	}
}

// main是程序的入口点，初始化Gin框架并设置路由。
func main() {
	r := gin.Default()
	r.LoadHTMLGlob("templates/*")

	// 定义根路径"/"的GET请求处理器。
	// 当用户访问根URL时，将渲染并返回"index.html"模板。
	r.GET("/", func(c *gin.Context) {
		c.HTML(http.StatusOK, "index.html", nil)
	})

	// 定义"/events"的GET请求处理器，用于处理事件流。
	r.GET("/events", handleEvents)

	// 启动一个goroutine定期生成通知消息并广播。
	go func() {
		for i := 0; ; i++ {
			time.Sleep(3 * time.Second)
			broadcastNotification(fmt.Sprintf("New Notification %d", i))
		}
	}()

	// 启动HTTP服务器，监听8080端口。
	r.Run(":8080")
}
